Skip to content

Notebook: your channels (labels first, then tag per unit) (Stage 1, PR 15) - #233

Merged
guijacquemet merged 4 commits into
mainfrom
claude/notebook-channels
Nov 9, 2026
Merged

guijacquemet merged 4 commits into
mainfrom
claude/notebook-channels

Conversation

@guijacquemet

@guijacquemet guijacquemet commented Nov 8, 2026 •

Copy link
Copy Markdown
Contributor

What and why

The "Your channels" screen, after the axis roles are confirmed (pictures are read only through confirmed roles). Labels first, then tagging per unit, in the owner's words: a label names what was stained, never the dye or the microscope slot.

  • A. Which labels did you image? One list of IDs with optional shown-as names. Slots = the largest channel count in any non-colour image; Add label adds more. Prefilled only from header names that are valid IDs as written and not generic (Ch1, C0, Channel 2, AF488, Cy5, DAPI, GFP, 488 nm...; a short documented regex list in channel_labels.GENERIC_PATTERNS). Look-alike spellings (case, space, -/_, one character) come back as a group with "Same label / Different labels / Decide later"; nothing is merged. Case collisions, duplicates, R/G/B and reserved names are refused at once with the reader's codes. Saved only on "Yes, these are the labels". The hint says that an unused slot still needs a label (for example unused).
  • B. Tag each channel. One row per unit (condition / repeat / technical repeat), one column per C index; each cell is a ~160 px safe thumbnail (PR 13 channel_strip: reduce, float32, own percentile contrast; Enlarge gives 1024 px), the C index, the quoted raw header name and a dropdown limited to the declared labels. Every position of every unit must get a label. One chip colour per label; a chip always shows the label ID, the shown-as name is its tooltip. A label can stand once per unit. A unit whose header names equal the labels exactly is pre-tagged, but only as a suggestion until one confirm per layout. Complete only when every position of every unit is tagged and every type answered. Labels used in k of n units say "used in k of n units: an analysis of X will be refused for the other units (A_SCOPE_INCOMPLETE)". A label sitting in different columns in different units is pointed out.
  • Image type is a per-unit column, nothing preselected; "colour (RGB)" is pre-ticked only when the header says RGB, and that pre-tick is saved only with the layout confirm.
  • One representative image per unit (first by sorted path), stated on the card; contrast per thumbnail stated; nothing inferred from pixels.
  • Separable pieces: LabelsCard (A), TagGrid (B) and ImageTypeColumn are self-contained classes that read and save through one AnswerStore; notebook_channels.py is the thin layout. Rules are pure modules (channel_labels, channel_answers, channel_units).
  • Draft file version 3 (contract section 18, CHANGELOG): a unit's channels may hold null (not tagged) or a declared channel ID; an empty string is refused. image_type may be channels; versions 1 and 2 are refused. Each label's header_names are derived from the tagged cells at every save. missing_confirmations adds unit_channel_untagged. Saved tags whose length no longer fits the image are not used (never stretched); carry_over keeps the answers of units that remain.

Owner decisions (2026-11-08)

  1. No "not imaged / empty" option. Removed from the dropdowns and from the draft format; the unit_channel_empty path and the "" draft state are gone (null still means not tagged). Every channel position of every unit needs a label the user declares in Step A (for example unused or Brightfield); Step B is complete only when every position has one. The Step A hint says so. Contract section 18, CHANGELOG and tests adjusted.
  2. Global "Image type" card kept for now; it is retired in PR 16. No change here.
  3. Same chip text everywhere. Step A colour chips used to show the display name while the grid chips showed the ID. Every chip now shows the ID; the display name is the tooltip.

Tests

tests/test_notebook_channels.py (headless widget tests) and tests/test_channel_labels.py (library and draft-file tests), including: dropdown without an empty option, an unused-label slot completes Step B, one missing label keeps it incomplete, an empty-string tag is refused in the file, chip shows ID with the display name as tooltip only.

  • After merging origin/main and these changes, the full python tools/check.py run: ruff check and ruff format clean, 4773 passed, 4 skipped, 0 failed in 270.84 s (0:04:30), then the code rules step. The 4 skips are the existing case-sensitive file system and file-mode skips.
  • An earlier full run in this session failed only ruff E501 (two over-long docstring lines from my edit and one test line); fixed, and the run above is the clean one.

Screenshots

Regenerated after the decisions (synthetic images; not committed): pr15-fresh, pr15-near-miss, pr15-partial, pr15-complete, pr15-resumed. The complete state uses an unused label for the third channel of the drug units.

Open UX questions

  1. Step 2's global "Image type" card still exists next to the per-unit column; retired in PR 16 (owner decision above).
  2. Mixed layouts (for example RGB units next to fluorescence units) are still refused earlier by the folder and axis checks, so the grid's mixed-layout rows are covered by library tests only.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Scma6W3LC11s3qjXHZuGDm

…R 15)

Step A lists the labels (what was stained), prefilled only from valid,
non-generic header names, with look-alike spellings grouped for the user
and case collisions refused at once. Step B is an image-first grid with a
thumbnail, quoted header name and a label dropdown per channel of each
unit, a per-unit image type with nothing preselected, one confirm per
header layout, and usage warnings for labels used in only some units.
The cards are separate pieces (labels, grid, image-type column) over one
answer store. Draft file version 3: null for not tagged, "" for not
imaged, image_type "channels"; header names derived from the tags.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Scma6W3LC11s3qjXHZuGDm
… everywhere (PR 15)

Owner decisions 2026-11-08: remove the not imaged / empty option, the empty-string
draft state and unit_channel_empty; unused slots need a label such as unused. Colour
chips now always show the ID, the shown-as name is the tooltip.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Scma6W3LC11s3qjXHZuGDm
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Scma6W3LC11s3qjXHZuGDm
@guijacquemet
guijacquemet marked this pull request as ready for review November 8, 2026 14:45
@guijacquemet
guijacquemet merged commit 631000e into main Nov 9, 2026
7 checks passed
@guijacquemet
guijacquemet deleted the claude/notebook-channels branch November 9, 2026 05:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants